目前为止,我们已经了解了用ProxyFactoryBean或是相似的factory bean显示的创建AOP代理。
Spring也允许我们使用“自动代理的”bean定义,它会自动代理被选贼的bean。它基于Spring的“bean后置处理器”的结构,后置处理可以在容器加载bean时修改bean的定义。
在这个模块,你在XML中定义了一些特殊的bean用来配置自动代理结构。这是你只需声明自动代理的目标,而不再需要使用ProxyFactoryBean
有两种方式可以实现这点:
使用自动代理创造器并引用当前上下文中的特殊的bean。 特殊的自动代理创建需要被单独处理;自动代理创建由源码级别的元数据属性驱动。

12.9.1 Autoproxy bean definitions

org.springframework.aop.framework.autoproxy包提供下列标准的自动代理创造器。

BeanNameAutoProxyCreator

BeanNameAutoProxyCreator类是一个BeanPostProcesser,可以为名字匹配字面值或是通配符的bean自动创建AOP代理。

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value="jdk*,onlyJdk"/>
    <property name="interceptorNames">
        <list>
            <value>myInterceptor</value>
        </list>
    </property>
</bean>

ProxyFactoryBean一样,它采用interceptorNames属性,而不是interceptor的数组,保证原型的advisor行为正确。这里的"interceptor"可以使advisors或任何advice类型。
和通常的自动代理一样,使用BeanNameAutoProxyCreator的重点是将相同的配置应用到多个对象上,到达最小配置的目的。对于在多个对象上应用声明性事务时,它是很常见的选择。
对于名字匹配的bean定义,比如上面例子中的"jdkMyBean"和"onlyJdk",就是普通的Bean定义的目标类。BeanNameAutoProxyCreator会自动的创建AOP代理。同一个通知会应用到匹配的bean上。注意如果使用的是advisor(而不是上例中的interceptor),那么可以对不同的bean应用不同的切点。

DefaultAdvisorAutoProxyCreator

更加常见和强大的自动代理创造器是DefaultAdvisorAutoProxyCreator。它会自动自动应用上下文中合格的advisor,不再需要指定advisor的bean定义。它和BeanNameAutoProxyCreator一样具有应用相同的配置到多个对象上的有点。
使用这个机制涉及:
指定一个DefaultAdvisorAutoProxyCreatorbean定义。
在用一个或想关联的上下文中指定一些Advisors。注意一定要是Advisor,而非interceptor或是advice。这是因为它要指明切点,并为每个通知检查合格的候选Bean定义。
DefualtAdvisorAutoProxyCreator会自动评估每个advisor中定义的切点,来确定为每个业务对象(比如"businessObject1"和"businessObject2")应用什么通知(如果存在的话)。
这意味着通知都会被应用到业务对象上。如果任何advisor中的切点都不匹配业务对象的方法,那将不会有对象被代理。如果有新添加的业务对象的bean定义,且匹配advisor,它们会自动被代理。
通常,自动代理具有让调用者无法获取未被通知的对象的特点。在这个上下文环境中使用getBean("businessObject1")会返回一个AOP代理,而不是目标的业务对象。(之前说的“内部bean”的方式也有这个好处)。

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>

<bean id="businessObject1" class="com.mycompany.BusinessObject1">
    <!-- Properties omitted -->
</bean>

<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>

DefualtAdvisorAutoProxyCreator在你想讲同一个通知应用到多个业务对象上时十分有效。一旦结构定义确定,你可以简单的田间新的业务对象而不用在指定代理的配置。你也可以很简单的添加其他的切面——比如,追踪或是监测性能的切面——只需要改动很小的配置。
DefaultAdvisorAutoProxyCreator支持过滤(对名字进行约束,只有符合的advisor会被评估,在同一个工厂中,可以使用多个不同配置的AdvisorAutoProxyCreator)和排序。Advisor可以实现org.springframework.core.Ordered接口来保证正确的顺序。上面例子中的TransactionAttributeSourceAdvisor已经配置了order值;more的设置未被排序的。

AbstractAdvisorAutoProxyCreator

它是DefaultAdvisorAutoProxyCreator的父类。你可以用它创建自己的自动代理创造器,在少数的一些情况下,弥补框架提供的DefaultAdvisorAutoProxyCreator的不足。

12.9.2 Using metadata-driven auto-proxying

一种特别重要的自动代理类型是由元数据驱动的。这和.NET的ServicedComponents是相似的编程模型。和在XML中定义元数据不同,事务管理和其他企业服务定义在源码级别的属性上。
这种情况下,你可以结合了解元数据属性的Advisor使用DefaultAdvisorAutoProxyCreator。元数据信息定义在候选的advisor的切点部分,而不是在自动代理创建类本身。
这实际上是DefaultAdvisorAutoProxyCreator的一个特例,但是值得去思考。(知道元数据的代码在advisor包含的切点中,而不是AOP框架自身。)
JPetStore示例应用(sun公司为了演示自己的J2EE而编写的一个宠物店的电子商务的例子)的/attributes目录展示了属性驱动的自动代理。这种情况下,没有必要使用TransactionProxyFactoryBean。由于使用了metadata-aware(了解元数据)的切点,简单的在业务对象上定义事务属性就足够了。在/WEB-INF/declarativeServices.xml中的bean定义包含了下面的代码。注意这都是通用的,可以在JPetStore之外使用:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributeSource">
        <bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
            <property name="attributes" ref="attributes"/>
        </bean>
    </property>
</bean>

<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>

DefaultAdvisorAutoProxyCreatorbean定义(名字不重要,因此被省略了)会自动在当前的上下文中选择符合的切点。在这个情况下,TranscationAttributeSourceAdvisor类型的"transcationAdvisor"bean定义,会被应用到带有transaction属性的类或者方法上。TransactionAttributeSourceAdvisor通过构造器依赖,依赖于TransactionInteceptor。这个例子通过自动装配解决了依赖问题。AttributesTransactiobnAttributeSource依赖于org.springframework.metadata.Attributes的接口的实现。在这里,"attributes"bean满足这个条件,它通过Jakarta Commons Attributes API来获取属性信息。(银行用程序代码必须已经被Commons Attributes 编译任务编译过。)
JPetStore示例应用的/annotation目录包含了一个相似的自动代理的例子,它由JDK1.5+注解驱动。下面的配置开启Spring的Transactional注解的自动检测,为包含该注解的bean隐式的创建代理。

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributeSource">
        <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
    </property>
</bean>

这里定义的TransactionInterceptor依赖于PlatformTranscationManager的定义,这个定义通常不在这个文件中(尽管它可以在这里定义),因为它取决于应用程序的事务要求(通常是 JTA,或Hibernate,或JDO或JDBC):

<bean id="transactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager"/>

如果你只需要声明事务管理,那么使用这些通用的XML定义会让Spring自动为所有具有事务属性的类和方法创建代理。你不需要直接和AOP打交道,这样的编程模型和.NET的ServicedComponents是很相似的。

这种机制是可拓展的。可以让自定义的属性创建自动代理。你只需要: 定义你自己的属性。
注定一个advisor,它有必要的通知,并且有一个会被含有自定属性的类或方法触发的切点。
这些的advisor可以对每个被通知的类都是不同的(比如,mixins):可以将advisor定义为原型,而不是单例。比如,之前所演示的Spring test包LockMixin引入拦截器,可以结合通用的DefaultIntroductionAdvisor使用:

<bean id="lockMixin" class="test.mixin.LockMixin" scope="prototype"/>

<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
        scope="prototype">
    <constructor-arg ref="lockMixin"/>
</bean>

注意:lockMixinlockableAdvisor都被定义成了原型。